#include "instructionsimple.h"



instructionsimple::instructionsimple(string typ, string instr, fonction* f, bool valid):type(typ),inst(instr),fun(f)
{
	
	if(!valid)
	{
		valide = 1;
		
		inst=trim(inst);
		flux_erreur.clear(); //On vide le flux d'erreur pour cette instruction
		flux_erreur<<typ<<" "<<instr<<endl<<"--->" ;
		string testErreur=flux_erreur.str();;
		if(type!="#" && type!="REPETE" && type!="FIN_REPETE" && inst[inst.length()-1]!=';')
		{
		flux_erreur<<" erreur syntaxe: missing ';' ";
		valide = 0;
		}
		else
		{
		inst=inst.substr(0,inst.find_last_of(";"));
		inst=trim(inst);
		
		if (type== "DECLARE") { VDeclare(); }
		else 
			if (type== "AFFECTE") { VAffecte(); }
			else
				if (type== "AFFICHE") { VAffiche(); }
				else
					if (type== "APPEL") { VAppel(); }
					else
						if (type== "RETOUR") { VRetour(); }
						else
							if (type== "#") {  }
							else
								if(type=="REPETE") { VRepete(); }
								else 
									if(type=="FIN_REPETE") {}
									else valide=false;
		}
		if (flux_erreur.str()!=testErreur) fun->errorLog(flux_erreur.str());
	}
	else
	{
		valide = 1;
		inst=inst.substr(0,inst.find_last_of(";"));
		inst=trim(inst);
	}
}

void instructionsimple::printInst()
{
	cout<<type<<" "<<inst<<endl;
}


string instructionsimple::translate()
{
	if(type=="#")
	{
		stringstream S;
		S<<"// "<<inst;
		return S.str();
	}
	if(type=="AFFICHE")
	{
		stringstream S;
		S<<"cout<<"<<inst<<" ;";
		return S.str();
	}
	if(type=="AFFECTE")
	{
		stringstream S;
		S<<elements[0]<<" = ";
		if(isExpression(inst.substr(inst.find_first_of(" ")))) //Traitement lorsqu'il y a une expression
		{
			//for(int i=1;i<elements.size();i++) S<<elements[i]<<" ";
			S<<translateExpression(inst.substr(inst.find_first_of(" ")));
		}
		else
		{
			S<<elements[1];
		}
		S<<" ;" ;
		return S.str();
	}
	if(type=="APPEL")
	{
		stringstream S;
		S<<elements[0]<<"(";
		for(int i=1;i<elements.size();i++) 
		{
			if (i<elements.size()-2) S<<elements[i]<<",";
			else  S<<elements[i];
		}
		S<<");";
		return S.str();
	}
	if(type=="DECLARE")
	{
		stringstream S;
		S<<"int "<<inst<<" ;";
		return S.str();
	}
	if(type=="RETOUR")
	{
		stringstream S;
		S<<"return ";
		if(isExpression(inst)) //Traitement lorsqu'il y a une expression
		{
			S<<translateExpression(inst);
		}
		else
		{
			S<<inst ;
		}
		S<<" ;" ;
		return S.str();
	}
	if(type=="REPETE")
	{
		static time_t date = time( NULL );
		date++;
		stringstream S;
		S<<"for(int i"<<date<<"=0;i"<<date<<"<"<<inst<<";i"<<date<<"++"<<"){";
		return S.str();
		date++;
	}
	if(type=="FIN_REPETE")
	{
		stringstream S;
		S<<"}";
		return S.str();
	}
	return "";
}

void instructionsimple::VDeclare()
{
	if (inst.length()>0)
	{
		inst=inst.substr(0,inst.find_last_of(";"));
		inst=trim(inst);
		

		if (isID(inst))
		{
				if (!fun->checkVar(inst)) 
				{
					fun->addVariable(inst);
					valide = 1;
					return;
				}
				else 
				{
					flux_erreur<<"erreur: déclarations multiples de "<<inst<<endl;
					valide = 0;
					return ;
				}
		}
		else 
		{
			flux_erreur<<"erreur: declaration de trop de variables"<<endl;
			valide = 0;
			return ;
		}

	}
	valide = 0;
}

void instructionsimple::VAffecte()
{
 
	//int nbID=0,nbOp=0;
	if (inst.length()>0)
	{
		if(isID(inst.substr(0,inst.find_first_of(" ")))) //Si le premier élément de l'affectation est un id
		{
			if(isExpression(inst.substr(inst.find_first_of(" ")))) //Si la suite est une expression
			{
				tokenize(inst,elements," "); //On initialise elements pour la trad plus tard
				
				if (fun->checkVar(elements[0]))
				{
					for(int i=1;i<elements.size();i++) 
					{
						if (isID(elements[i]) && !fun->isInitialized(elements[i])) //Si la variable n'a été déclarée et initialisée
						{
							flux_erreur<<"error : la variable "<<elements[i]<<" n'est pas initialisée"<<endl;
							valide = 0;
							return ;
						}
					}
					fun->initialize(elements[0]);
					valide = 1;
					return ;
				}
				else 
				{
					flux_erreur<<"error : la variable "<<elements[0]<<" n'est pas déclarée"<<endl;
					valide = 0;
					return ;
				}
			}
			else
			{
				flux_erreur<<"error : l'expression "<<inst.substr(inst.find_first_of(" "))<<" n'est pas valide"<<endl;
				valide = 0;
				return ;
			}
		}
		else
		{
			flux_erreur<<"error : l'expression "<<inst.substr(0,inst.find_first_of(" "))<<" n'est pas valide"<<endl;
			valide = 0;
			return ;
		}
	}
}

void instructionsimple::VAffiche()
{
	if (inst.length()>0)
	{
		if ((isID(inst)&&fun->isInitialized(inst)) || isChaine(inst)) valide = 1;
		else
		{
			if(isID(inst) && !fun->isInitialized(inst)) flux_erreur<<"error : "<<inst<<" n'a pas été déclarée ou initialisée"<<endl;
			else flux_erreur<<"error : Affichage non conforme "<<endl;
			valide = 0;
		}
	}
}

void instructionsimple::VAppel()
{
	if (inst.length()>0)
	{
		tokenize(inst,elements," ");
		//On vérifie que la fonction a été déclarée auparavant
		if (fun->checkFonction(elements[0]))
		{
			int nombreParametreRequis = fun->getNbParaFonction(elements[0]);
			int nombreParametre = elements.size()-1;
			if (nombreParametreRequis>nombreParametre) //Pas assez
			{
				flux_erreur<<"error : Paramètre manquant pour l'appel a la fonction "<<elements[0]<<endl;
				valide = 0;
			}
			else
			{
				if (nombreParametreRequis<nombreParametre) //Trop
				{
					flux_erreur<<"error : Trop de paramètres pour l'appel a la fonction "<<elements[0]<<endl;
					valide = 0;
				}
				else //Juste ce qu'il faut
				{
					
					for(int i=1;i<elements.size();i++)
					{
						if ((isID(elements[i]) && fun->isInitialized(elements[i]))|| isNumber(elements[i]))
						{
							valide = 1;
						}
						else
						{
							flux_erreur<<"error : "<<elements[i]<<" n'est pas déclarée "<<endl;
							valide = 0;
						}
					}
				}
			}
			
			
		}
		else
		{
			flux_erreur<<"error : Fonction "<<elements[0]<<" non déclarée"<<endl;
			valide = 0;
		}
	}
}

void instructionsimple::VRetour()
{
	
	if (inst.length()>0)
	{
		if (isID(inst) && fun->isInitialized(inst))
		{
			valide = 1;
		}
		else
		{
			if (isID(inst)) 
			{
				flux_erreur<<"error : la variable "<<inst<<" n'a pas été déclarée ni initialisée"<<endl;
				valide = 0;
				return ;
			}
			else
			{
				if (isNumber(inst))
				{
					valide = 1;
					return ;
				}
				else 
				{ 
					if (isExpression(inst))
					{
						valide = 1;
						return ;
					}
					else
					{
						flux_erreur<<"error : l'expression "<<inst<<" n'est pas valide"<<endl;
						valide = 0;
						return ;
					}
				}
			}
		}
	}
	flux_erreur<<"error : RETOUR "<<inst<<" est mal formé"<<endl;
	valide = 0;
}

void instructionsimple::VRepete()
{
	if (inst.length()>0)
	{
		if(isID(inst))
		{
			if(!fun->isInitialized(inst))
			{
				flux_erreur<<"error : Argument non initialisé : "<<inst<<endl;
				valide = 0;
				return ;
			}
			else
			{
				valide = 1;
				return ;
			}
		}
		else
		{
			if(!isNumber(inst))
			{
				flux_erreur<<"error : Argument invalide : "<<inst<<endl;
				valide = 0;
				return ;
			}
			else
			{
				valide = 1;
				return ;
			}
			
		}
	}
	flux_erreur<<"error : REPETE "<<inst<<" est mal formé"<<endl;
	valide = 0;
}


void instructionsimple::tokenize(const string& str, vector< string >& tokens, const string& delimiters)
{
	
  // Skip delimiters at beginning.
    string::size_type lastPos = str.find_first_not_of(delimiters, 0);
    // Find first "non-delimiter".
    string::size_type pos     = str.find_first_of(delimiters, lastPos);
    while (string::npos != pos || string::npos != lastPos)
    {
        // Found a token, add it to the vector.
        tokens.push_back(str.substr(lastPos, pos - lastPos));
        // Skip delimiters.  Note the "not_of"
        lastPos = str.find_first_not_of(delimiters, pos);
        // Find next "non-delimiter"
        pos = str.find_first_of(delimiters, lastPos);
    }
}

bool instructionsimple::isID(const string & id)
{
	regex_t preg;
	const char *noSpecial = "[^_a-zA-Z0-9]";
	const char *alphaBegin ="^[a-zA-Z][a-zA-Z0-9]*";
	regcomp (&preg, noSpecial, REG_NOSUB | REG_EXTENDED);
	int match;
	match=regexec (&preg, id.c_str(), 0, NULL, 0);
	regfree(&preg);
	
	switch (match)
	{
		case 0: {/*Match: Il y a des caractère spéciaux dans la chaine*/
			return 0;
			break;
		}
		case REG_NOMATCH:{/*NotMatch : Pas de caractères spéciaux*/
			
			//On teste si la chaine commence par un caractère alpha 
			
			regcomp (&preg, alphaBegin, REG_NOSUB | REG_EXTENDED);
			if (regexec (&preg, id.c_str(), 0, NULL, 0) == 0){ regfree(&preg); return 1;}
			else { regfree(&preg); return 0;}
			break;
		}
		default : return 0;
	}
}

bool instructionsimple::isOpBin(const string & op)
{
  if (op.size()>1) return 0;
  else 
  {
    if (op=="+") return 1;
    if (op=="-") return 1;
    if (op=="*") return 1;
    if (op=="/") return 1;
    else return 0;
  }
}

bool instructionsimple::isNumber(const string& arg1)
{
	const char * arg=arg1.c_str();
	char * a;
	int test = strtol(arg,&a,10);
	
	if (test!=0L) 
	{
		
		return 1;
	}
	else
	{
		if (arg1=="0") return 1;
		else 0;
	}
	
}

bool instructionsimple::isExpression(const string& arg)
{
	//cout<<arg<<endl;
	string tmp=trim(arg);
	if (arg.length()>0)
	{
		
		vector<string> leselements;
		
		//On tokenize avec le séparateur " "
		tokenize(arg,leselements," ");
		
		//Comptage
		int nombreOperateur=0, nombreArgument=0;
		for(int i=0;i<leselements.size();i++)
		{
			if (isID(leselements[i])||isNumber(leselements[i])) nombreArgument++;
			if (isOpBin(leselements[i])) nombreOperateur++;
		}
		
		
		if(leselements.empty())
		{
			flux_erreur<<"error : Erreur de syntaxe "<<endl;
			return 0;
		}
		//cout<<arg<<" nbop="<<nombreOperateur<<"nbar="<<nombreArgument<<endl;
		//Si le premier élément est un opérateur binaire
		
		if(isOpBin(leselements[0]))
		{
			
			//On rechere le prochain élément qui doit être un nombre ou un id
			//On enlève l'opérateur binaire 
			tmp=tmp.substr(1);
			if (isID(leselements[1]) || isNumber(leselements[1]))
			{
				
				//Ici deux cas possible soit il y a une autre expression, soit l'expression se finit
				if (isID(leselements[2]) || isNumber(leselements[2]))
				{
					//On a une expression du type - X Y
					if (leselements[0]=="/" && isNumber(leselements[2]) && leselements[2]=="0")
					{
						flux_erreur<<"error : Division par zéro"<<endl;
					}
					if (leselements.size()==3) return 1;
					else return 0;
				}
				else 
				{
					//On a une expression plus complexe - X * X Y
					if (isOpBin(leselements[2])) return isExpression(tmp.substr(tmp.find_first_of(leselements[2])));
					else return 0;
				}
			}
			else //Cas d'un +- exp exp exp
			{
				if (isOpBin(leselements[1])) 
				{
					
				/*	if(nombreOperateur+1==nombreArgument) 
					{
						cout<<"titi"<<endl;
						return isExpression(tmp.substr(tmp.find_first_of(leselements[1]),tmp.find_last_of(leselements[leselements.size()-1])-1));
					}
					else */
					//	if (nombreOperateur==nombreArgument)
					//	{
							if(leselements.size()>=3)
							{
								int indiceFinExpression=-1;
								nombreOperateur=1;
								for(int i=1;i<leselements.size();i++)
								{
									if((i+2)>(leselements.size()-1)) break;
									if ((isID(leselements[i])||isNumber(leselements[i])) && (isID(leselements[i+1])||isNumber(leselements[i+1])))
									{
										if ((isOpBin(leselements[i+2]) || isID(leselements[i+2]) || isNumber(leselements[i+2])))
										{
											//cout<<i+nombreOperateur<<" "<<leselements[i+nombreOperateur]<<endl;
											if(isOpBin(leselements[i+nombreOperateur-1])) 
											{
												flux_erreur<<"error : paramètres manquant pour l'opération : "<<leselements[1]<<endl;
												return 0;
											}
											else indiceFinExpression=i+nombreOperateur;
											break;
										}
									}
									else nombreOperateur++;
								}
								
								stringstream arg1,arg2;
								for(int i=1;i<indiceFinExpression;i++) arg1<<leselements[i]<<" ";
								for(int i=indiceFinExpression;i<leselements.size();i++) arg2<<leselements[i]<<" ";
								//cout<<"Argument1 ="<<arg1.str()<<"Argument2="<<arg2.str()<<endl;
								if(trim(arg1.str())!="" && trim(arg2.str())!="") return isExpression(arg1.str()) && isExpression(arg2.str());
								else
								{
									flux_erreur<<"error : paramètres manquant pour l'opération : "<<leselements[1]<<endl;
									return 0;
								}
							}
							else return 0;
					//	}
					//return 0;
				}
				else
				{
					return 0;
				}
			}
			
		}
		if ((isNumber(leselements[0]) || isID(leselements[0])) && leselements.size()==1) return 1;
		else return 0;
		
		
	}
	else return 0;
}

bool instructionsimple::isChaine(const string& arg)
{
	if (arg[0]=='"' && arg[arg.length()-1]=='"')
	{
		
		regex_t preg;
		const char *noSpecial = "[\"]";
		regcomp (&preg, noSpecial, REG_NOSUB | REG_EXTENDED);
		string tmp = arg.substr(1,arg.length()-2);  //On retire les guillemets aux extrémités
		//cout<<tmp<<endl;
		int match=regexec (&preg, tmp.c_str(), 0, NULL, 0);
		regfree(&preg);
		
		if (match == 0)
		{
			return 0;
		}
		else return 1;
	}
	else
	{
		//cout<<arg<<endl;
		return 0;
	}
}

bool instructionsimple::isValid()
{
	return valide;
}

string instructionsimple::translateExpression(const string& arg)
{
	string tmp=trim(arg);
	
	vector<string> leselements;
	tokenize(tmp,leselements," ");
	int deb,fin;
	//cout<<"'"<<tmp<<"'-----------------"<<endl;
	
	//for(int i=0;i<leselements.size();i++) cout<<i<<" "<<leselements[i]<<leselements.size()<<endl;
	stringstream S;
	//if(isID(tmp)||isNumber(tmp)) return tmp;
	//cout<<elements.size()<<endl;
	if (leselements.size()>0)
	{
		if(isOpBin(leselements[0]))
		{
			
			if(leselements.size()==3) 
			{
				//cout<<"trois"<<endl;
				S<<""<<leselements[1]<<""<<leselements[0]<<""<<leselements[2]<<"";
				return S.str();
			}
			else
			{
				int indiceFinExpression;
				int nombreOperateur=1;
				if ((isID(leselements[1])||isNumber(leselements[1]))) indiceFinExpression=2;
				else
				{
					for(int i=1;i<leselements.size();i++)
					{
						
						if ((isID(leselements[i])||isNumber(leselements[i])) && (isID(leselements[i+1])||isNumber(leselements[i+1])))
						{
							//cout<<"#"<<leselements[i]<<leselements[i+1]<<leselements[i+2]<<"#"<<leselements.size()<<endl;
							indiceFinExpression=i+nombreOperateur;
							break;
						}
						else nombreOperateur++;
					}
				}
				stringstream arg1,arg2;
				for(int i=1;i<indiceFinExpression;i++) arg1<<leselements[i]<<" ";
				for(int i=indiceFinExpression;i<leselements.size();i++) arg2<<leselements[i]<<" ";
				
				//cout<<"IndiceFin="<<indiceFinExpression<<"Argument1 ="<<arg1.str()<<"Argument2="<<arg2.str()<<endl;
				S<<"("<<translateExpression(arg1.str())<<")"<<leselements[0]<<"("<<translateExpression(arg2.str())<<")";
				return S.str();
			
			}
			
		}
		else
		if(isID(leselements[0]) || isNumber(leselements[0])) return leselements[0];
		
	}
	return "";
}



